//! 复数定义

use std::ops::{Add, Div, Mul, Sub};

/// 复数集合
#[derive(Copy, Clone, Debug)]
pub struct Complex {
    r: f32,
    i: f32,
}

impl Complex {
    pub fn new() -> Self {
        Complex { r: 0_f32, i: 0_f32 }
    }

    pub fn abs(&self) -> f32 {
        self.r * self.r + self.i * self.i
    }

    pub fn real(&self) -> f32 {
        self.r
    }

    pub fn img(&self) -> f32 {
        self.i
    }

    pub fn pow(&self, n: usize) -> Self {
        if n == 0 {
            return Self { r: 1.0, i: 0.0 };
        }

        let tt = *self;
        let mut t = *self;
        for _ in 0..n - 1 {
            t = tt * t;
        }

        t
    }
}

impl From<i32> for Complex {
    fn from(t: i32) -> Self {
        Complex {
            r: t as f32,
            i: 0_f32,
        }
    }
}

impl From<f32> for Complex {
    fn from(t: f32) -> Self {
        Complex { r: t, i: 0_f32 }
    }
}

impl From<(i32, i32)> for Complex {
    fn from(t: (i32, i32)) -> Self {
        Complex {
            r: t.0 as f32,
            i: t.1 as f32,
        }
    }
}

impl From<(f32, f32)> for Complex {
    fn from(t: (f32, f32)) -> Self {
        Complex { r: t.0, i: t.1 }
    }
}

impl Add for Complex {
    type Output = Complex;

    fn add(self, rhs: Self) -> Self::Output {
        Complex {
            r: self.r + rhs.r,
            i: self.i + rhs.i,
        }
    }
}

impl Sub for Complex {
    type Output = Complex;

    fn sub(self, rhs: Self) -> Self::Output {
        Complex {
            r: self.r - rhs.r,
            i: self.i - rhs.i,
        }
    }
}

impl Mul for Complex {
    type Output = Complex;

    fn mul(self, rhs: Self) -> Self::Output {
        Complex {
            r: self.r * rhs.r - self.i * rhs.i,
            i: self.r * rhs.i + self.i * rhs.r,
        }
    }
}

impl Div for Complex {
    type Output = Complex;

    fn div(self, rhs: Self) -> Self::Output {
        let div = rhs.i * rhs.i + rhs.r * rhs.r;
        Complex {
            r: (self.r * rhs.r + self.i * rhs.i) / div,
            i: (self.i * rhs.r - self.r * rhs.i) / div,
        }
    }
}

#[macro_export]
macro_rules! comp {
    () => {
        Complex::new()
    };

    ($x:expr) => {
        Complex::from($x)
    };

    ($x:expr, $y:expr) => {
        Complex::from(($x, $y))
    };
}
